package com.youlu.campus.service.university.impl;

import com.alibaba.fastjson.JSON;
import com.mongodb.client.result.UpdateResult;
import com.youlu.campus.base.exception.BusinessException;
import com.youlu.campus.entity.UniversityInfo;
import com.youlu.campus.entity.VO.req.ImportUniversityExcelVO;
import com.youlu.campus.entity.VO.req.ImportUniversityInfoExcelVO;
import com.youlu.campus.entity.VO.req.UniversityInfoQueryVO;
import com.youlu.campus.service.university.UniversityInfoService;
import com.youlu.campus.service.university.repository.UniversityInfoRepository;
import com.youlu.campus.service.utils.IkAnalyzerUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.*;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

@Slf4j
@Service
public class UniversityInfoServiceImpl implements UniversityInfoService {
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private StringRedisTemplate redisTemplate;

    private String UNIVEARSITY_KEY = "com.luyou.universityInfo:%s";

    private final static String LOGO = "https://qiniu.gqgood.com/imgfb2fbd3021624202bb1d5386ecb1eb79university-default-logo.jpg";

    @Override
    public Page<UniversityInfo> list(UniversityInfoQueryVO req) {
        log.info(":>>> 开始查询大学列表:{}", JSON.toJSONString(req));
        if (Objects.isNull(req)) {
            log.error(":>> 请求参数错误:{}", JSON.toJSONString(req));
            throw new BusinessException("参数错误");
        }
        Query query;
        if (StringUtils.isNotBlank(req.getName())) {

//            Pattern pattern = Pattern.compile("^.*" + req.getName() + ".*$", Pattern.CASE_INSENSITIVE);
//            query.addCriteria(Criteria.where("name").regex(pattern));
            TextCriteria textCriteria = TextCriteria.forDefaultLanguage();
            Set<String> names = IkAnalyzerUtil.getSegText(req.getName(), true);
            String ak = IkAnalyzerUtil.getSegTextStr(names);
            textCriteria.matching(ak);
            query = TextQuery.queryText(textCriteria).sortByScore();
        } else {
            query = new Query();
        }
        if (StringUtils.isNotBlank(req.getProvince())) {
            query.addCriteria(Criteria.where("province").is(req.getProvince()));
        }
        if (StringUtils.isNotBlank(req.getValue())) {
            query.addCriteria(Criteria.where("value").is(req.getValue()));
        }
        if (Objects.nonNull(req.getInBlackList())) {
            query.addCriteria(Criteria.where("inBlackList").is(req.getInBlackList()));
        }
        if (Objects.nonNull(req.getShowSearchUserSignUp())) {
            if (req.getShowSearchUserSignUp()) {
                query.addCriteria(Criteria.where("dataType").in(1, 2));
            } else {
                query.addCriteria(Criteria.where("dataType").is(3));
            }
        } else {
            query.addCriteria(Criteria.where("dataType").in(1, 2, 3));
        }
        PageRequest pageRequest = PageRequest.of(req.getPage() - 1, req.getPageSize());
        if (Objects.nonNull(req.getDeleted())) {
            query.addCriteria(Criteria.where("deleted").is(req.getDeleted()));
        } else {
            query.addCriteria(Criteria.where("deleted").ne(true));
        }

        long count = mongoTemplate.count(query, UniversityInfo.class);
        if (count == 0) {
            return PageableExecutionUtils.getPage(new ArrayList<>(), pageRequest, () -> 0);
        }
        List<UniversityInfo> infos = mongoTemplate.find(query.with(pageRequest), UniversityInfo.class);
        infos.forEach(universityInfo -> {
            if (universityInfo.getDataType() == 3) {
                universityInfo.setShowSearchUserSignUp(Boolean.FALSE);
            }
        });
        return PageableExecutionUtils.getPage(infos, pageRequest, () -> count);
    }

    @Override
    public List<UniversityInfo> listByIds(List<String> ids) {
        log.info(":>>> 开始查询大学列表 listByIds :{}", ids);
        Query query = new Query().addCriteria(Criteria.where("id").in(ids));
        List<UniversityInfo> universityInfos = mongoTemplate.find(query, UniversityInfo.class);
        return universityInfos;
    }

    @Override
    public boolean create(UniversityInfo req) {
        log.info(":>>> 新增大学信息:{}", JSON.toJSONString(req));
        if (Objects.isNull(req) || StringUtils.isBlank(req.getName()) || StringUtils.isBlank(req.getValue()) || StringUtils.isBlank(req.getProvince()) ||
                StringUtils.isBlank(req.getLogo())) {
            log.error(":>>> 创建大学信息参数错误");
            throw new BusinessException("创建大学信息参数错误");
        }
        Query query = new Query().addCriteria(Criteria.where("name").is(req.getName()));
        boolean exist = mongoTemplate.exists(query, UniversityInfo.class);
        if (exist) {
            log.error(":>>> 数据已经存在");
            throw new BusinessException("大学名重复数据已经存在");
        }
        Query query1 = new Query().addCriteria(Criteria.where("value").is(req.getValue()));
        boolean exist1 = mongoTemplate.exists(query1, UniversityInfo.class);
        if (exist1) {
            log.error(":>>> 数据已经存在:大学编码:{}", req.getValue());
            throw new BusinessException("大学编码重复数据已经存在");
        }
        req.setId(null);
        if (Objects.nonNull(req.getShowSearchUserSignUp()) && req.getShowSearchUserSignUp()) {
            req.setDataType(1);
        } else {
            req.setDataType(3);
        }
        req.setCreatedTime(new Date());
        Set<String> names = IkAnalyzerUtil.getSegText(req.getName(), true);
        req.setNameKeywords(names);
        req.setNameKeys(IkAnalyzerUtil.getSegTextStr(names));
        mongoTemplate.insert(req);
        return true;
    }

    @Override
    public boolean update(UniversityInfo req) {
        log.info(":>>> 修改大学信息:{}", JSON.toJSONString(req));
        if (Objects.isNull(req) || StringUtils.isBlank(req.getId())) {
            log.error(":>>> 创建大学信息参数错误");
            throw new BusinessException("创建大学信息参数错误");
        }
        Query query = new Query().addCriteria(Criteria.where("id").is(req.getId()));
        Update update = new Update();
        if (StringUtils.isNotBlank(req.getName())) {
            update.set("name", req.getName());
            Set<String> names = IkAnalyzerUtil.getSegText(req.getName(), true);
            update.set("nameKeywords", names);
            update.set("nameKeys", IkAnalyzerUtil.getSegTextStr(names));
        }
        if (StringUtils.isNotBlank(req.getValue())) {
            update.set("value", req.getValue());
        }
        if (StringUtils.isNotBlank(req.getLogo())) {
            update.set("logo", req.getLogo());
        }
        if (StringUtils.isNotBlank(req.getProvince())) {
            update.set("province", req.getProvince());
        }
        if (StringUtils.isNotBlank(req.getUserCount())) {
            update.set("userCount", req.getUserCount());
        }
        if (StringUtils.isNotBlank(req.getType())) {
            update.set("type", req.getType());
        }
        if (StringUtils.isNotBlank(req.getLevel())) {
            update.set("level", req.getLevel());
        }
        if (Objects.nonNull(req.getMerged())) {
            update.set("merged", req.getMerged());
        }
        if (Objects.nonNull(req.getEstablishedTime())) {
            update.set("establishedTime", req.getEstablishedTime());
        }
        if (Objects.nonNull(req.getEmploymentRate())) {
            update.set("employmentRate", req.getEmploymentRate());
        }
        if (!CollectionUtils.isEmpty(req.getTags())) {
            update.set("tags", req.getTags());
        }
        if (StringUtils.isNotBlank(req.getCity())) {
            update.set("city", req.getCity());
        }
        if (Objects.nonNull(req.getUserTotal())) {
            update.set("userTotal", req.getUserTotal());
        }
        if (Objects.nonNull(req.getInBlackList())) {
            update.set("inBlackList", req.getInBlackList());
        }
        if (StringUtils.isNotBlank(req.getEnName())) {
            update.set("enName", req.getEnName());
        }
        if (Objects.nonNull(req.getShowSearchUserSignUp())) {
            if (req.getShowSearchUserSignUp()) {
                update.set("dataType", 1);
            } else {
                update.set("dataType", 3);
            }
        }
        update.set("updatedTime", new Date());
        UpdateResult updateResult = mongoTemplate.updateFirst(query, update, UniversityInfo.class);
        boolean re = updateResult.getModifiedCount() > 0 ? true : false;
        log.info(":>>> 修改大学:{},结果:{}", req.getId(), re);
        return re;

    }

    @Override
    public boolean delete(String id) {
        log.info(":>>> 开始删除大学:{}", id);
        Query query = new Query().addCriteria(Criteria.where("id").is(id));
        Update update = new Update();
        update.set("deleted", true);
        update.set("updatedTime", new Date());
        return mongoTemplate.updateFirst(query, update, UniversityInfo.class).getModifiedCount() > 0 ? true : false;
    }

    @Override
    public UniversityInfo findOne(String id) {
        log.info(":>>> 开始查询大学:{}", id);
        Query query = new Query().addCriteria(Criteria.where("id").is(id));
        UniversityInfo universityInfo = mongoTemplate.findOne(query, UniversityInfo.class);
        if (Objects.nonNull(universityInfo)) {
            if (universityInfo.getDataType() == 3) {
                universityInfo.setShowSearchUserSignUp(Boolean.FALSE);
            }
            return universityInfo;
        }
        return null;
    }

    @Override
    public UniversityInfo getCache(String id) {
        String key = String.format(UNIVEARSITY_KEY, id);
        UniversityInfo universityInfo = null;
        Object o = redisTemplate.opsForValue().get(key);
        if (Objects.isNull(o)) {
            universityInfo = this.findOne(id);
            if (Objects.nonNull(universityInfo)) {
                redisTemplate.opsForValue().set(key, JSON.toJSONString(universityInfo), 1, TimeUnit.HOURS);
                return universityInfo;
            }
            return null;
        } else {
            universityInfo = JSON.parseObject((String) o, UniversityInfo.class);
            return universityInfo;
        }
    }

    @Override
    public void importUniversity(List<ImportUniversityExcelVO> importUniversityExcelList) {
        log.info("【导入学校数据】 start");
        if (CollectionUtils.isEmpty(importUniversityExcelList)) {
            return;
        }
        importUniversityExcelList.stream().forEach(importUniversityExcel -> {
            String id = importUniversityExcel.id;
            String name = importUniversityExcel.name;
            String enName = importUniversityExcel.enName;
            UniversityInfo universityInfo = this.findOne(id);
            if (Objects.isNull(universityInfo)) {
                Query query = new Query();
                query.addCriteria(Criteria.where("name").is(name));
                universityInfo = this.mongoTemplate.findOne(query, UniversityInfo.class);
                if (Objects.isNull(universityInfo)) {
                    log.warn("【导入学校数据】 未找到该学校->{}", name);
                    return;
                }
            }
            if (Objects.nonNull(universityInfo)) {
                log.warn("【导入学校数据】 已查找到学校->{} enName ->{}", name, enName);
                universityInfo.setEnName(enName);
                if (StringUtils.isBlank(universityInfo.getNameKeys())) {
                    Set<String> names = IkAnalyzerUtil.getSegText(name, true);
                    universityInfo.setNameKeywords(names);
                    universityInfo.setNameKeys(IkAnalyzerUtil.getSegTextStr(names));
                }
                this.mongoTemplate.save(universityInfo);
            }
        });
        log.info("【导入学校数据】 end");
    }

    @Override
    public UniversityInfo saveOrUpdate(UniversityInfo updateUniversity) {
        String name = updateUniversity.getName();
        if (StringUtils.isBlank(name)) {
            throw new BusinessException("学校名称不能为空");
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("name").is(name.trim()));
        UniversityInfo universityInfo = this.mongoTemplate.findOne(query, UniversityInfo.class);
        if (Objects.nonNull(universityInfo)) {
            return universityInfo;
        }
        name = name.trim();
        query = new Query();
        query.addCriteria(Criteria.where("value").is(name));
        universityInfo = this.mongoTemplate.findOne(query, UniversityInfo.class);
        if (Objects.nonNull(universityInfo)) {
            return universityInfo;
        }
        query.addCriteria(Criteria.where("name").is(name));
        Date now = new Date();
        Update update = new Update();
        update.setOnInsert("createdTime", now);
        update.setOnInsert("deleted", false);
        update.set("updatedTime", now);
        update.set("dataType", 3);
        Set<String> names = IkAnalyzerUtil.getSegText(name, true);
        update.set("nameKeywords", names);
        update.set("nameKeys", IkAnalyzerUtil.getSegTextStr(names));
        FindAndModifyOptions findAndModifyOptions = new FindAndModifyOptions();
        findAndModifyOptions.returnNew(Boolean.TRUE);
        findAndModifyOptions.upsert(Boolean.TRUE);
        return this.mongoTemplate.findAndModify(query, update, findAndModifyOptions, UniversityInfo.class);
    }

    @Override
    public void importBatchUniversity(List<ImportUniversityInfoExcelVO> importBatchUniversityExcelList) {
        log.info("【批量导入学校】start UniversityInfoService.importBatchUniversity size ->{}", importBatchUniversityExcelList.size());
        Date now = new Date();
        importBatchUniversityExcelList.forEach(batchUniversity -> {
            if (StringUtils.isBlank(batchUniversity.getCode())) {
                return;
            }
            String name = batchUniversity.getName().trim();
            Query query = new Query();
            query.addCriteria(Criteria.where("name").is(name));
            boolean exists = this.mongoTemplate.exists(query, UniversityInfo.class);
            if (!exists) {
                Update update = new Update();
                update.set("value", batchUniversity.getCode());
                update.set("enName", batchUniversity.getEnName());
                update.set("province", batchUniversity.getProvince());
                update.set("city", batchUniversity.getCity());
                update.set("type", batchUniversity.getType());
                update.set("userTotal", batchUniversity.getUserTotal());
                update.set("logo", LOGO);
                update.set("dataType", 1);
                update.setOnInsert("createdTime", now);
                update.setOnInsert("deleted", false);
                update.set("updatedTime", now);
                Set<String> names = IkAnalyzerUtil.getSegText(name, true);
                update.set("nameKeywords", names);
                update.set("nameKeys", IkAnalyzerUtil.getSegTextStr(names));
                FindAndModifyOptions findAndModifyOptions = new FindAndModifyOptions();
                findAndModifyOptions.upsert(Boolean.TRUE);
                findAndModifyOptions.returnNew(Boolean.TRUE);
                this.mongoTemplate.findAndModify(query, update, findAndModifyOptions, UniversityInfo.class);
            }
            log.info("【批量导入学校】已存在 UniversityInfoService.importBatchUniversity name ->{}", batchUniversity.getName());
        });
        log.info("【批量导入学校】end UniversityInfoService.importBatchUniversity end");

    }

    @Override
    public boolean deletePshysics(String id) {
        log.info(":>>> 开始删除大学:{}", id);
        Query query = new Query().addCriteria(Criteria.where("id").is(id));
        return mongoTemplate.remove(query, UniversityInfo.class).getDeletedCount() > 0 ? true : false;
    }

}
